// Copyright Epic Games, Inc. All Rights Reserved.

#include "LyraBotCreationComponent.h"
#include "LyraGameMode.h"
#include "Engine/World.h"
#include "GameFramework/PlayerState.h"
#include "GameModes/LyraExperienceManagerComponent.h"
#include "Development/LyraDeveloperSettings.h"
#include "Character/LyraPawnExtensionComponent.h"
#include "AIController.h"
#include "Kismet/GameplayStatics.h"
#include "Character/LyraHealthComponent.h"

#include UE_INLINE_GENERATED_CPP_BY_NAME(LyraBotCreationComponent)

/**
 * 构造函数
 */
ULyraBotCreationComponent::ULyraBotCreationComponent(const FObjectInitializer& ObjectInitializer)
	: Super(ObjectInitializer)
{
}

/**
 * 开始播放
 */
void ULyraBotCreationComponent::BeginPlay()
{
	Super::BeginPlay(); // 调用父类实现

	// 监听经验加载完成
	AGameStateBase* GameState = GetGameStateChecked<AGameStateBase>(); // 获取游戏状态
	ULyraExperienceManagerComponent* ExperienceComponent = GameState->FindComponentByClass<ULyraExperienceManagerComponent>(); // 查找经验管理器组件
	check(ExperienceComponent); // 检查组件有效性
	// 注册经验加载低优先级回调
	ExperienceComponent->CallOrRegister_OnExperienceLoaded_LowPriority(FOnLyraExperienceLoaded::FDelegate::CreateUObject(this, &ThisClass::OnExperienceLoaded));
}

/**
 * 经验加载完成回调
 * @param Experience 加载的经验定义
 */
void ULyraBotCreationComponent::OnExperienceLoaded(const ULyraExperienceDefinition* Experience)
{
#if WITH_SERVER_CODE
	// 如果有权限，在服务器上创建机器人
	if (HasAuthority())
	{
		ServerCreateBots(); // 服务器创建机器人
	}
#endif
}

#if WITH_SERVER_CODE

/**
 * 服务器创建机器人实现
 */
void ULyraBotCreationComponent::ServerCreateBots_Implementation()
{
	// 如果机器人控制器类为空，返回
	if (BotControllerClass == nullptr)
	{
		return;
	}

	RemainingBotNames = RandomBotNames; // 初始化剩余机器人名称

	// 确定要生成多少机器人
	int32 EffectiveBotCount = NumBotsToCreate; // 有效机器人数量

	// 给开发者设置一个覆盖的机会
	if (GIsEditor) // 如果在编辑器中
	{
		const ULyraDeveloperSettings* DeveloperSettings = GetDefault<ULyraDeveloperSettings>(); // 获取开发者设置
		
		// 如果覆盖机器人数量
		if (DeveloperSettings->bOverrideBotCount)
		{
			EffectiveBotCount = DeveloperSettings->OverrideNumPlayerBotsToSpawn; // 使用覆盖值
		}
	}

	// 给URL一个覆盖的机会
	if (AGameModeBase* GameModeBase = GetGameMode<AGameModeBase>()) // 获取游戏模式
	{
		// 从选项字符串中获取机器人数量
		EffectiveBotCount = UGameplayStatics::GetIntOption(GameModeBase->OptionsString, TEXT("NumBots"), EffectiveBotCount);
	}

	// 创建机器人
	for (int32 Count = 0; Count < EffectiveBotCount; ++Count)
	{
		SpawnOneBot(); // 生成一个机器人
	}
}

/**
 * 创建机器人名称
 * @param PlayerIndex 玩家索引
 * @return 机器人名称
 */
FString ULyraBotCreationComponent::CreateBotName(int32 PlayerIndex)
{
	FString Result; // 结果字符串
	// 如果还有剩余名称
	if (RemainingBotNames.Num() > 0)
	{
		// 随机选择一个名称索引
		const int32 NameIndex = FMath::RandRange(0, RemainingBotNames.Num() - 1);
		Result = RemainingBotNames[NameIndex]; // 获取名称
		RemainingBotNames.RemoveAtSwap(NameIndex); // 移除已使用的名称
	}
	else
	{
		//@TODO: PlayerId目前只为玩家初始化
		PlayerIndex = FMath::RandRange(260, 260+100); // 随机玩家索引
		Result = FString::Printf(TEXT("Tinplate %d"), PlayerIndex); // 生成默认名称
	}
	return Result; // 返回名称
}

/**
 * 生成一个机器人
 */
void ULyraBotCreationComponent::SpawnOneBot()
{
	FActorSpawnParameters SpawnInfo; // 生成参数
	SpawnInfo.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn; // 总是生成
	SpawnInfo.OverrideLevel = GetComponentLevel(); // 覆盖层级
	SpawnInfo.ObjectFlags |= RF_Transient; // 设置临时标志
	// 在世界中生成AI控制器
	AAIController* NewController = GetWorld()->SpawnActor<AAIController>(BotControllerClass, FVector::ZeroVector, FRotator::ZeroRotator, SpawnInfo);

	// 如果控制器生成成功
	if (NewController != nullptr)
	{
		ALyraGameMode* GameMode = GetGameMode<ALyraGameMode>(); // 获取Lyra游戏模式
		check(GameMode); // 检查游戏模式有效性

		// 如果玩家状态有效
		if (NewController->PlayerState != nullptr)
		{
			// 设置玩家名称
			NewController->PlayerState->SetPlayerName(CreateBotName(NewController->PlayerState->GetPlayerId()));
		}

		GameMode->GenericPlayerInitialization(NewController); // 通用玩家初始化
		GameMode->RestartPlayer(NewController); // 重启玩家

		// 如果控制器有Pawn
		if (NewController->GetPawn() != nullptr)
		{
			// 查找Pawn扩展组件
			if (ULyraPawnExtensionComponent* PawnExtComponent = NewController->GetPawn()->FindComponentByClass<ULyraPawnExtensionComponent>())
			{
				PawnExtComponent->CheckDefaultInitialization(); // 检查默认初始化
			}
		}

		SpawnedBotList.Add(NewController); // 添加到已生成列表
	}
}

/**
 * 移除一个机器人
 */
void ULyraBotCreationComponent::RemoveOneBot()
{
	// 如果已生成机器人列表不为空
	if (SpawnedBotList.Num() > 0)
	{
		// 目前随机移除一个机器人，因为它们都一样；可以根据原因移除高技能或低技能等
		const int32 BotToRemoveIndex = FMath::RandRange(0, SpawnedBotList.Num() - 1); // 随机选择要移除的索引

		AAIController* BotToRemove = SpawnedBotList[BotToRemoveIndex]; // 获取要移除的机器人
		SpawnedBotList.RemoveAtSwap(BotToRemoveIndex); // 从列表中移除

		// 如果机器人有效
		if (BotToRemove)
		{
			// 如果能找到健康组件，自毁它，否则只销毁Actor
			if (APawn* ControlledPawn = BotToRemove->GetPawn()) // 获取控制的Pawn
			{
				// 查找健康组件
				if (ULyraHealthComponent* HealthComponent = ULyraHealthComponent::FindHealthComponent(ControlledPawn))
				{
					// 注意，目前这不太理想：当控制器被销毁时玩家状态消失，死亡动画等能力会立即中断
					HealthComponent->DamageSelfDestruct(); // 自毁伤害
				}
				else
				{
					ControlledPawn->Destroy(); // 销毁Pawn
				}
			}

			// 销毁控制器（会导致登出等）
			BotToRemove->Destroy(); // 销毁控制器
		}
	}
}

#else // !WITH_SERVER_CODE

/**
 * 服务器创建机器人实现（客户端版本）
 */
void ULyraBotCreationComponent::ServerCreateBots_Implementation()
{
	ensureMsgf(0, TEXT("Bot functions do not exist in LyraClient!")); // 确保失败，提示机器人功能不存在
}

/**
 * 生成一个机器人（客户端版本）
 */
void ULyraBotCreationComponent::SpawnOneBot()
{
	ensureMsgf(0, TEXT("Bot functions do not exist in LyraClient!")); // 确保失败，提示机器人功能不存在
}

/**
 * 移除一个机器人（客户端版本）
 */
void ULyraBotCreationComponent::RemoveOneBot()
{
	ensureMsgf(0, TEXT("Bot functions do not exist in LyraClient!")); // 确保失败，提示机器人功能不存在
}

#endif